package com.sl.shiro;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sl.mapper.UserMapper;
import com.sl.pojo.Role;
import com.sl.pojo.RoleRoute;
import com.sl.pojo.Route;
import com.sl.pojo.User;
import com.sl.service.RoleRouteService;
import com.sl.service.RoleService;
import com.sl.service.RouteService;
import com.sl.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.HashSet;

import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Slf4j
public class UserRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private RoleRouteService roleRouteService;
    @Autowired
    private RouteService routeService;

    /**
     * 提供帐户信息，返回认证信息
     * @param authenticationToken
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException  {
        log.info("---------------------登录认证开始----------------------");
        String userName=(String)authenticationToken.getPrincipal();
        log.info("获取username:"+userName);
        User user = userService.findByUsername(userName);
        if (null == user ) {
            throw new UnknownAccountException("找不到用户（" + userName + "）的帐号信息");
        }
        log.info("获取user"+JSON.toJSONString(user));
        if(user.getDeleted().equals(1)) {
            //用户被锁定就抛异常.||删除,不能登录
            throw new LockedAccountException("用户已经离职，请联系管理员");
        }
        SecurityUtils.getSubject().getSession().setAttribute("user",user );
        //密码可以通过SimpleHash加密，然后保存进数据库。
        //此处是获取数据库内的账号、密码、盐值，保存到登陆信息info中
        //以下信息：来自数据库...例子先用3个值。加严值。用最后//4.盐值：自己设定。因为用户名唯一。可以// ByteSource credentialsSalt = ByteSource.Util.bytes(userName);
        //1.认证的实体信息。。user.getUsername(),2.密码：user.getPassword()
        //3.RealmName：当前的Realm的对象name，调用父类的getName()方法
        //密码比对：通过AuthenticatingRealm的createtialsMatcher的属性来进行密码的比对
       // Boolean login = userService.login(user);

        SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(
                user.getUsername(),
                user.getPassword(),
                ByteSource.Util.bytes(user.getUsername()) ,//4.盐值：自己设定。这里使用：用户名
                getName()); //realm name
        return info;
    }
    /**提供用户信息，返回权限信息*/
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        log.info("---------------------权限认证开始----------------------");
        //1.从这里能拿到登陆的用户信息。。new SimpleAuthenticationInfo。第一个属性是username。user的话。就是user
        String userName=(String) principals.getPrimaryPrincipal();
        //2.利用登陆的用户信息。。来判断当前用户的角色和权限
        Set<String> roleSet =new HashSet<>();
        User user = userService.findByUsername(userName);
        Integer roleId = user.getRoleId();
        log.info("user:" + userName);
        //得到所有的角色。放入SET集合
        Role role = roleService.findById(roleId);
        roleSet.add(role.getRoleName());

        Set<String>  permissionSet=new HashSet<>();
        //所有的权限permission
        List<RoleRoute> roleRouteList = roleRouteService.findByRoleId(roleId);
        log.info("roleRouteList" + JSON.toJSONString(roleRouteList));
        for (RoleRoute roleRoute : roleRouteList) {
            //王宁把中间表的的perm设置为。子类。
            Integer routeId = roleRoute.getRouteId();
            Route route = routeService.findById(routeId);
            //route中的path和component。都是。看实际情况
            String path = route.getPath();
            permissionSet.add(path);
        }
        //3.设置器roles的属性
        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
        // 将角色名称组成的Set提供给授权info
        info.setRoles(roleSet);
        // 将权限名称组成的Set提供给info
        info.setStringPermissions(permissionSet);
       /* //权限集合放入session
        Subject subject = SecurityUtils.getSubject();
        subject.getSession().setAttribute("pemissionSet",roleRouteList);*/
        return info;
    }
}
